﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "../macro/head.h"
#include "../tools/head.h"
#include "bzip2_impl.h"

#if defined( XOS_IOS_SIMULATOR )
#include "../../../../xosbin/lib/ios_simulator/bzip2/include/head.h"
#elif defined( XOS_IOS_STATIC )
#include "../../../../xosbin/lib/ios_static/bzip2/include/head.h"
#elif defined( XOS_MAC )
#include "../../../../xosbin/lib/mac/bzip2/include/head.h"
#elif defined( XOS_LINUX64 )
#include "../../../../xosbin/lib/linux64/bzip2/include/head.h"
#elif defined( XOS_ANDROID )
#include "../../../../xosbin/lib/android/bzip2/include/head.h"
#elif defined( XOS_LINUX )
#include "../../../../xosbin/lib/linux/bzip2/include/head.h"
#elif defined( XOS_WIN32 )
#include "../../../../xosbin/lib/win32/bzip2/include/head.h"
#elif defined( XOS_WIN64 )
#include "../../../../xosbin/lib/x64/bzip2/include/head.h"
#endif

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 

namespace xos_compress
{
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static bzip2_impl::POOL * pool_ptr = 0;

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//

	void * my_bzalloc( void * p, int m, int n )
	{
		return g_pSysData->m_pAlloc->my_malloc( m * n );
	}

	void my_bzfree( void * p, void * pData )
	{
		g_pSysData->m_pAlloc->my_free( pData );
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//

	bzip2_impl::bzip2_impl()
	{
	}

	bzip2_impl::~bzip2_impl()
	{
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 

    int bzip2_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
		int ret = 0;
		if( pppPool )
		{
			*pppPool = &pool_ptr;
		}
		if( pppList )
		{
			*pppList = 0;
		}
		return ret;
    }

	int bzip2_impl::init()
	{
		int ret = 0;
		return ret;
	}

	int bzip2_impl::term()
	{
		int ret = 0;
		return ret;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 

	// 
	// 解压
	// 
	int bzip2_impl::un_compress( char * lpszDest, int nDestLen, int * lpnDestLen, const char * lpszSrc, int nSrcLen )
	{
		int ret = 0;

		unsigned int destLen = (unsigned int)nDestLen;
		char * src = (char *)lpszSrc;

		if( 0 == ret )
		{
			ret = my_BZ2_bzBuffToBuffDecompress( lpszDest, &destLen, src, nSrcLen, 0, 0 );
		}

		if( ( 0 == ret ) && lpnDestLen )
		{
			*lpnDestLen = destLen;
		}

		return ret;
	}

	// 
	// 压缩
	// 
	int bzip2_impl::compress( char * lpszDest, int nDestLen, int * lpnDestLen, const char * lpszSrc, int nSrcLen, bool bLast )
	{
		int ret = 0;

		unsigned int destLen = ( unsigned int )nDestLen;
		char * src = (char *)lpszSrc;

		if( 0 == ret )
		{
			ret = my_BZ2_bzBuffToBuffCompress( lpszDest, &destLen, src, nSrcLen, 5, 0, 30 );
		}

		if( ( 0 == ret ) && lpnDestLen )
		{
			*lpnDestLen = destLen;
		}

		return ret;
	}

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int bzip2_impl::un_compress( xos_box::i_buf * pDestBuf, xos_box::i_buf * pSrcBuf )
    {
        int ret = 0;
        int nDestBufSize = 0, nDestLen = 0, nDestOutLen = 0, nSrcLen = 0;
        const char * lpszSrc = pSrcBuf->get_data( 0, 0, &nSrcLen );
        char * lpszDest = pDestBuf->get_data( 0, 0, &nDestLen );
        nDestBufSize = xos_box::i_buf::BUF_SIZE - nDestLen;
        ret = un_compress( lpszDest, nDestBufSize, &nDestOutLen, lpszSrc, nSrcLen );
        if( 0 == ret )
        {
            nDestLen = nDestLen + nDestOutLen;
            pDestBuf->set_len( nDestLen );
        }
        return ret;
    }

	int bzip2_impl::compress( xos_box::i_buf * pDestBuf, xos_box::i_buf * pSrcBuf, bool bLast )
	{
		int ret = 0;
		int nDestBufSize = 0, nDestLen = 0, nDestOutLen = 0, nSrcLen = 0;
		const char * lpszSrc = pSrcBuf->get_data( 0, 0, &nSrcLen );
		char * lpszDest = pDestBuf->get_data( 0, 0, &nDestLen );
		nDestBufSize = xos_box::i_buf::BUF_SIZE - nDestLen;
		ret = compress( lpszDest, nDestBufSize, &nDestOutLen, lpszSrc, nSrcLen, bLast );
		if( 0 == ret )
		{
			nDestLen = nDestLen + nDestOutLen;
			pDestBuf->set_len( nDestLen );
		}
		return ret;
	}

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int bzip2_impl::un_compress( xos_box::i_list * pDestList, xos_box::i_list * pSrcList )
    {
        int ret = 0;

        xos_box::i_buf * pDest = 0;
        xos_box::i_buf * pSrc = 0;

        while( ( 0 == ret ) && ( pSrc = ( xos_box::i_buf * )pSrcList->front( 0 ) ) )
        {
			pDest = g_pSysData->m_pContainer->buf();
            ret = un_compress( pDest, pSrc );
            if( 0 == ret )
            {
                pDestList->push_back( pDest );
                pSrcList->pop_front();
                pDest = 0;
            }
            else
            {
                pSrc = 0;
            }
            xos_stl::release_interface( pDest );
            xos_stl::release_interface( pSrc );
        }

        return ret;
    }

    int bzip2_impl::compress( xos_box::i_list * pDestList, xos_box::i_list * pSrcList )
    {
        int ret = 0;

        xos_box::i_buf * pDest = 0;
        xos_box::i_buf * pSrc = 0;

        while( ( 0 == ret ) && ( pSrc = ( xos_box::i_buf * )pSrcList->front( 0 ) ) )
        {
			pDest = g_pSysData->m_pContainer->buf();
            xos_box::i_buf * pEnd = ( xos_box::i_buf * )pSrcList->back( 0 );
            ret = compress( pDest, pSrc, pSrc == pEnd );
            if( 0 == ret )
            {
                pDestList->push_back( pDest );
                pSrcList->pop_front();
                pDest = 0;
            }
            else
            {
                pSrc = 0;
            }
            xos_stl::release_interface( pDest );
            xos_stl::release_interface( pSrc );
        }

        return ret;
    }

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 

	int bzip2_impl::my_BZ2_bzBuffToBuffCompress(
		char*         dest,
		unsigned int* destLen,
		char*         source,
		unsigned int  sourceLen,
		int           blockSize100k,
		int           verbosity,
		int           workFactor )
	{
		bz_stream strm;
		int ret;

		if( dest == NULL || destLen == NULL ||
			source == NULL ||
			blockSize100k < 1 || blockSize100k > 9 ||
			verbosity < 0 || verbosity > 4 ||
			workFactor < 0 || workFactor > 250 )
			return BZ_PARAM_ERROR;

		if( workFactor == 0 ) workFactor = 30;
		strm.bzalloc = my_bzalloc;
		strm.bzfree = my_bzfree;
		strm.opaque = NULL;
		ret = BZ2_bzCompressInit( &strm, blockSize100k,
			verbosity, workFactor );
		if( ret != BZ_OK ) return ret;

		strm.next_in = source;
		strm.next_out = dest;
		strm.avail_in = sourceLen;
		strm.avail_out = *destLen;

		ret = BZ2_bzCompress( &strm, BZ_FINISH );
		if( ret == BZ_FINISH_OK ) goto output_overflow;
		if( ret != BZ_STREAM_END ) goto errhandler;

		/* normal termination */
		*destLen -= strm.avail_out;
		BZ2_bzCompressEnd( &strm );
		return BZ_OK;

	output_overflow:
		BZ2_bzCompressEnd( &strm );
		return BZ_OUTBUFF_FULL;

	errhandler:
		BZ2_bzCompressEnd( &strm );
		return ret;
	}

	int bzip2_impl::my_BZ2_bzBuffToBuffDecompress(
		char*         dest,
		unsigned int* destLen,
		char*         source,
		unsigned int  sourceLen,
		int           sml,
		int           verbosity )
	{
		bz_stream strm;
		int ret;

		if( dest == NULL || destLen == NULL ||
			source == NULL ||
			( sml != 0 && sml != 1 ) ||
			verbosity < 0 || verbosity > 4 )
			return BZ_PARAM_ERROR;

		strm.bzalloc = my_bzalloc;
		strm.bzfree = my_bzfree;
		strm.opaque = NULL;
		ret = BZ2_bzDecompressInit( &strm, verbosity, sml );
		if( ret != BZ_OK ) return ret;

		strm.next_in = source;
		strm.next_out = dest;
		strm.avail_in = sourceLen;
		strm.avail_out = *destLen;

		ret = BZ2_bzDecompress( &strm );
		if( ret == BZ_OK ) goto output_overflow_or_eof;
		if( ret != BZ_STREAM_END ) goto errhandler;

		/* normal termination */
		*destLen -= strm.avail_out;
		BZ2_bzDecompressEnd( &strm );
		return BZ_OK;

	output_overflow_or_eof:
		if( strm.avail_out > 0 ) {
			BZ2_bzDecompressEnd( &strm );
			return BZ_UNEXPECTED_EOF;
		}
		else {
			BZ2_bzDecompressEnd( &strm );
			return BZ_OUTBUFF_FULL;
		};

	errhandler:
		BZ2_bzDecompressEnd( &strm );
		return ret;
	}

}
